#include"head.h"

using namespace std;

template<typename Te>
class Matrix{
	size_t shape_col;
	size_t shape_row;

	bool isT;
	size_t iter_current_x, iter_current_y;
	size_t line_index;

	vector<vector<Te>> contain;

	inline void turned(size_t& row, size_t& col) {
		if (isT) {
			size_t temp = row;
			row = col;
			col = temp;
		}
	}

	inline Te vecMul(Te* L, Te* R, size_t len) {
		Te result = 0;

		for (size_t i = 0; i < len; i++) {
			result += L[i] * R[i];
		}

		return result;
	}

	/*vector<T>& operator[](size_t row) {
		return contain[row];
	}*/

public:
	
	Matrix() :shape_row(0), shape_col(0), isT(0), iter_current_x(0), iter_current_y(0), line_index(0) {}
	Matrix(vector<vector<Te>> init) :shape_row(0), shape_col(0), isT(0), iter_current_x(0), iter_current_y(0), line_index(0) {
		shape_row = init.size();
		shape_col = init[0].size();
		contain = init;
	}
	Matrix(vector<Te> init) :shape_row(0), shape_col(0), isT(0), iter_current_x(0), iter_current_y(0), line_index(0) {
		shape_row = 1;
		shape_col = init.size();
		contain.push_back(init);
	}

	Matrix(size_t rowLen, size_t colLen) :shape_row(0), shape_col(0), isT(0), iter_current_x(0), iter_current_y(0), line_index(0) {
		shape_col = colLen;
		shape_row = rowLen;

		contain.resize(rowLen);
		for (size_t i = 0; i < rowLen; i++) {
			contain[i].resize(colLen, 0);
		}
	}

	size_t Shape_row() {
		if (isT) return shape_col;
		return shape_row;
	}

	size_t Shape_col() {
		if (isT) return shape_row;
		return shape_col;
	}

	Te* for_each(bool refresh = 0) {
		if (refresh) {
			iter_current_x = iter_current_y = 0;
			return nullptr;
		}

		if (iter_current_x == shape_col) iter_current_x = 0; iter_current_y++;
		if (iter_current_y == shape_row) {
			iter_current_y = 0;
			return nullptr;
		}

		return &(contain[iter_current_y][iter_current_x++]);
	}

	vector<Te>* each_line(bool refresh = 0) {
		if (refresh) {
			line_index = 0;
			return nullptr;
		}

		if (line_index == shape_row) {
			line_index = 0;
			return nullptr;
		}

		return &(contain[line_index++]);
	}

	Te operator()(size_t row, size_t col) {
		turned(row, col);
		return contain[row][col];
	}

	Matrix& T_f() {
		isT = !isT;
		return *this;
	}

	Matrix& dot(Matrix& right, Matrix* result = nullptr) {
		if (this->Shape_col() != right.Shape_row()) return *this;

		size_t Len = this->Shape_col();
		vector<vector<Te>> temp;
		Te* vecL = new Te[Len];
		Te* vecR = new Te[Len];

		for (size_t i = 0; i < this->Shape_row(); i++) {
			vector<Te> sum;
			for (size_t s = 0; s < Len; s++) vecL[s] = (*this)(i, s);

			for (size_t j = 0; j < Len; j++) {
				for (size_t s = 0; s < Len; s++) vecR[s] = right(s, i);
				sum.push_back(vecMul(vecL, vecR, Len));
			}

			temp.push_back(sum);
		}

		delete[] vecL;
		delete[] vecR;

		if (result) {
			*result = temp;
			return *result;
		}
		contain = temp;
		return *this;
	}

	Matrix& operator*(Te num) {
		for_each(1);
		Te* temp = for_each();
		while (temp != nullptr) {
			*temp *= num;
			temp = for_each();
		}
		for_each(1);
		return *this;
	}

	Matrix& operator+(Te num) {
		for_each(1);
		Te* temp = for_each();
		while (temp != nullptr) {
			*temp += num;
			temp = for_each();
		}
		for_each(1);
		return *this;
	}

};